package yunc.checkData;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import yunc.checkData.exception.NoFileException;
import yunc.checkData.pojo.HyBaseZjtide;
import yunc.checkData.pojo.T021;
import yunc.checkData.pojo.T022;
import yunc.checkData.pojo.T023;
import yunc.checkData.utils.IOutil;
import yunc.checkData.utils.JDBCUtils;
import yunc.checkData.utils.MD5Util;
import yunc.checkData.utils.PropertiesUtil;

import java.io.File;
import java.util.*;

public class ZJtoDB {

    static ArrayList<File> allFileList = new ArrayList<>();
    static ArrayList<String> readFile = new ArrayList<>();
    //获取已经读取过的文件
    static List<String> readedFileList = IOutil.read("C:\\潮位标准文件\\已读文件标记\\readedFile.txt");
    private static Logger logger = LoggerFactory.getLogger(ZJtoDB.class.getName());
    public static void main(String[] args) {

        //读取配置文件
        Properties config = PropertiesUtil.load("config.properties");
        String oriFileParentPath = config.getProperty("ori.parent.path");
        String checkFileParentPath = config.getProperty("check.parent.path");


        //获取所有标准文件并将文件分类至三个数组中
        ArrayList<File> allFiles = getAllFiles(oriFileParentPath);

        //检查读取的目录是空目录
        try {
            checkFileListEmpty(oriFileParentPath,allFiles);
        } catch (NoFileException e) {
            e.printStackTrace();
        }

        //收集所有以T023开头的文件
        File[] oriFiles023 = addFileToList(allFiles);

        //遍历所有T023标准文件，遍历时分别获得其对应的T022、T021开头的文件，最后将结果写到
        if (oriFiles023.length!=0) {
            HashMap<String, Integer> targetMap = new HashMap<>();
            for (int i = 0; i < oriFiles023.length; i++) {
                String fileName = oriFiles023[i].getName();  //获取文件名称  T0232009.QHW
                String month = "20" + fileName.substring(4, 6) + "-" + fileName.substring(6, 8);  //获取月份  2020-09
                String suffix = fileName.split("\\.")[1];
                String stationName = getStationNameFromFileSuffix(suffix);

                //C:\潮位标准文件\标准文件\2020\12\T0232012.BAJ
                //C:\潮位标准文件\标准文件\2020\12\T0222012.BAJ
                //C:\潮位标准文件\标准文件\2020\12\T0212012.BAJ
                //C:\潮位标准文件\质控后文件\2020\12\T0232012.BAJ
                //C:\潮位标准文件\质控后文件\2020\12\T0222012.BAJ
                //C:\潮位标准文件\质控后文件\2020\12\T0212012.BAJ
                String ori023Path = oriFiles023[i].getAbsolutePath();   //获取文件的绝对路径
                String ori022Path = ori023Path.replace("T023", "T022");
                String ori021Path = ori023Path.replace("T023", "T021");
                String check023Path = ori023Path.replace("\\标准文件\\", "\\质控后文件\\");
                String check022Path = ori022Path.replace("\\标准文件\\", "\\质控后文件\\");
                String check021Path = ori021Path.replace("\\标准文件\\", "\\质控后文件\\");


                //如果该文件已经被同步过，则跳过
                if (readedFileList.contains(ori023Path)){
                    continue;
                }
                //检查标准文件对应的质控文件件是否存在，不存在，则跳过，并将异常记录写进日志
                if (!new File(check023Path).exists()) {
//                    System.out.println("原文件 " + ori023Path + " 对应的质检文件-- "+  check023Path +" 不存在,请在质检后重新执行此程序");
                    logger.error("原文件 " + ori023Path + " 对应的质检文件-- "+  check023Path +" 不存在,请在质检后重新执行此程序");
                    continue;
                }
                //基础集合
                targetMap = new T023(ori023Path).getData().getData();

                //分别获取三种逐分、5分钟与整点数据中已修改的值，后面根据规则整合
                HashMap<String, Integer> different023 = getTideDataDifferentValue(ori023Path,check023Path,"T023");
                HashMap<String, Integer> different022 = getTideDataDifferentValue(ori022Path,check022Path,"T022");
                HashMap<String, Integer> different021 = getTideDataDifferentValue(ori021Path,check021Path,"T021");


                //根据规则,将质检后修改的值插入到 逐分质检数据中 , 按照小时级别 -> 5分钟 -> 1分钟 几个层次进行覆盖
                different021.putAll(different022);
                different021.putAll(different023);
                targetMap.putAll(different021);

                //插入数据库
                ArrayList<HyBaseZjtide> hyBaseZjtides = new ArrayList<>();
                //    先删除旧数据，以免导入数据重复--幂等性保证
                String deleteSql = "delete from hy_base_zjtide where to_char(\"timestamp\",'yyyy-MM')=? and stationname=?";
                Integer deleteNum = JDBCUtils.executeUpdate(deleteSql, Arrays.asList(new String[]{month,stationName}));
//                System.out.println();
                logger.info("共删除了" + deleteNum + " 条已存在的数据");

                //    获取需要关联的数据
                Map<String, HashMap<String, String>> depthInfosMap = getDepthInfo(month, stationName);
                Map<String, HashMap<String, String>> radarsMap = getRadar(month, stationName);
                Integer updateNum=0;
                //    遍历map生成 HyBaseZjtide 对象实例
                Iterator it = targetMap.entrySet().iterator();
                while (it.hasNext()) {
                    Map.Entry entry = (Map.Entry) it.next();
                    String key = (String) entry.getKey();
                    Integer value = (Integer) entry.getValue();
                    HyBaseZjtide hyBaseZjtide = new HyBaseZjtide();
                    if ("CWY-02".equals(stationName) || "CWY-03".equals(stationName) || "CWY-04".equals(stationName) || "CWY-06".equals(stationName)) {
                        hyBaseZjtide = setDepthInfos(key,stationName,value,depthInfosMap);
                    } else if ("CWY-05".equals(stationName) || "CWY-07".equals(stationName)){
                        hyBaseZjtide = setRadars(key,stationName,value,radarsMap);
                    }
                    hyBaseZjtides.add(hyBaseZjtide);

                    //批量提交
                    if (hyBaseZjtides.size() == 500) {
                        updateNum += JDBCUtils.executeBatchUpdate("hy_base_zjtide", hyBaseZjtides);
                        hyBaseZjtides.clear();
                    }
                }
                updateNum += JDBCUtils.executeBatchUpdate("hy_base_zjtide", hyBaseZjtides);
//                System.out.println("共插入了" + updateNum + " 条数据");
                logger.info("共插入了" + updateNum + " 条数据");
            }
            //记录已读入的数据
//            readedFileList.addAll(readFile);
            IOutil.write("C:\\潮位标准文件\\已读文件标记\\readedFile.txt",readFile);
        }else {
            logger.error("标准文件的文件夹下没有文件，请添加文件");
        }

    }


    /**
     * 获取深度仪给定月份的给定仪器的去重后的所有数据
     * @param month
     * @param stationname
     * @return
     */
    private static Map<String,HashMap<String,String>> getDepthInfo(String month, String stationname){

        String sql = SqlBox.depthInfoSql;
        String[] params = {month,stationname};
        return getMD5MapfromList(sql,Arrays.asList(params));
    }

    /**
     * 获取雷达给定月份的给定仪器的去重后的所有数据
     * @param month
     * @param stationname
     * @return
     */
    private static Map<String,HashMap<String,String>> getRadar(String month, String stationname){

        String sql = SqlBox.radarSql;
        String[] params = {month,stationname};

        return getMD5MapfromList(sql,Arrays.asList(params));
    }

    /**
     * 获取雷达给定月份的给定仪器的去重后的所有数据
     * @param month
     * @param stationname
     * @return
     */
    private static Map<String,HashMap<String,String>> getCsi(String month, String stationname){

        String sql = SqlBox.csiSql;
        String[] params = {month,stationname};

        return getMD5MapfromList(sql,Arrays.asList(params));
    }

    /**
     * TODO
     * @param sql
     * @param params
     * @return
     */
    private static Map<String,HashMap<String,String>> getMD5MapfromList(String sql, List params){
        Map<String,HashMap<String,String>> infosMap = new HashMap<>();

        List<HashMap<String, String>> infoMaps = JDBCUtils.handExecuteQuery(sql, params);

        for (int i = 0; i < infoMaps.size(); i++) {
            String timestamp1 = infoMaps.get(i).get("timestamp").substring(0,19);
            String stationname1 = infoMaps.get(i).get("stationname");
            String md5 = MD5Util.md5(timestamp1 + stationname1);
            infosMap.put(md5,infoMaps.get(i));
        }
        return infosMap;
    }

    /**
     * 比较两个map，找出两个map中不同的值.如果map1与map2中同一个key的value不相同，则返回这个key在map2中的value。
     * @param map1
     * @param map2
     * @return 新的map
     */
    public static HashMap<String, Integer> getDifferentEntry(Map<String, Integer> map1, Map<String, Integer> map2){

        HashMap<String, Integer> different = new HashMap<>();
        Iterator it = map1.entrySet().iterator();
        String key = null;
        Integer value = null;
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            key = (String) entry.getKey();
            value = (Integer) entry.getValue();
            if (!value.equals(map2.get(key))){
                different.put(key, map2.get(key));
            }
        }
        return different;
    }

    private static HyBaseZjtide setDepthInfos(String key,String stationName, Integer value, Map<String, HashMap<String, String>> depthInfosMap){
        HyBaseZjtide hyBaseZjtide = new HyBaseZjtide(key,stationName,value);
        if (depthInfosMap.get(hyBaseZjtide.getId()) != null){
            hyBaseZjtide.setCrYear(Integer.parseInt(depthInfosMap.get(hyBaseZjtide.getId()).get("cryear")));
            hyBaseZjtide.setCrDay(Integer.parseInt(depthInfosMap.get(hyBaseZjtide.getId()).get("crday")));
            hyBaseZjtide.setDataTimes(Integer.parseInt(depthInfosMap.get(hyBaseZjtide.getId()).get("datatimes")));
            hyBaseZjtide.setrBRPressureInfo(Double.parseDouble(depthInfosMap.get(hyBaseZjtide.getId()).get("rbrpressureinfo")));
            hyBaseZjtide.setUmsTs(depthInfosMap.get(hyBaseZjtide.getId()).get("ums_ts_"));
        }else {
            logger.error("仪器 " + stationName + "在 " + key + " 时段的对应数值没有上报，请检查设备");
        }
        return hyBaseZjtide;
    }

    private static HyBaseZjtide setRadars(String key,String stationName, Integer value, Map<String, HashMap<String, String>> radarsMap){
        HyBaseZjtide hyBaseZjtide = new HyBaseZjtide(key,stationName,value);
        if (radarsMap.get(hyBaseZjtide.getId()) != null){
            hyBaseZjtide.setCrYear(Integer.parseInt(radarsMap.get(hyBaseZjtide.getId()).get("cryear")));
            hyBaseZjtide.setCrDay(Integer.parseInt(radarsMap.get(hyBaseZjtide.getId()).get("crday")));
            hyBaseZjtide.setDataTimes(Integer.parseInt(radarsMap.get(hyBaseZjtide.getId()).get("datatimes")));
            hyBaseZjtide.setMachineID(Integer.parseInt(radarsMap.get(hyBaseZjtide.getId()).get("machineid")));
            hyBaseZjtide.setDepthMVrs(hyBaseZjtide.getDepthM());
            hyBaseZjtide.setLevelM(Double.parseDouble(radarsMap.get(hyBaseZjtide.getId()).get("level_m")));
            hyBaseZjtide.setsDM(Double.parseDouble(radarsMap.get(hyBaseZjtide.getId()).get("sd_m")));
            hyBaseZjtide.setUmsTs(radarsMap.get(hyBaseZjtide.getId()).get("ums_ts_"));
        }else {
            logger.error("仪器 " + stationName + "在 " + key + " 时段的对应数值没有上报，请检查设备");
        }
        return hyBaseZjtide;
    }

    private static Integer getDataTimesFromTimeStamp(String timestamp){
        //2020-08-01 01:00:00
        int hour = Integer.parseInt(timestamp.substring(11, 13));
        int minute = Integer.parseInt(timestamp.substring(14, 16));
        return  hour*60+minute;
    }

    private static String getStationNameFromHYcode(String hycode){
        String stationname="";
        if ("44A4".equals(hycode)) stationname="CWY-06";
        if ("44A5".equals(hycode)) stationname="CWY-05";
        if ("44A6".equals(hycode)) stationname="CWY-04";
        if ("44A7".equals(hycode)) stationname="CWY-07";
        if ("44A8".equals(hycode)) stationname="CWY-03";
        if ("44A9".equals(hycode)) stationname="CWY-02";

        return stationname;
    }

    private static String getStationNameFromFileSuffix(String suffix){
        String stationname="";
        if ("BAJ".equals(suffix)) stationname="CWY-06";
        if ("QHW".equals(suffix)) stationname="CWY-05";
        if ("SKO".equals(suffix)) stationname="CWY-04";
        if ("DMS".equals(suffix)) stationname="CWY-07";
        if ("SHY".equals(suffix)) stationname="CWY-03";
        if ("DYU".equals(suffix)) stationname="CWY-02";

        return stationname;
    }


    private static ArrayList<File> getAllFiles(String filePath) {
        File[] files = new File(filePath).listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                getAllFiles(file.getPath());
            }
            if (file.isFile()) {
                allFileList.add(file);
            }
        }
        return allFileList;
    }

    private static void checkFileListEmpty(String path, List<File> fileList) throws NoFileException {
        if (fileList.size()==0) {
            throw new NoFileException(path);
        }
    }


    private static File[] addFileToList(List<File> files){
        ArrayList<File> allFilesT023 = new ArrayList<>();
        for (File file : files) {
            if("T023".equals(file.getName().substring(0,4))){
                allFilesT023.add(file);
            }
        }
        return allFilesT023.toArray(new File[allFilesT023.size()]);
    }

    /**
     * 对比标准文件与质控文件,找出标准文件在质控后有修改的值
     * @param oriPath
     * @param checkPath
     * @param type
     * @return 返回修改了的值的map
     */
    private static HashMap<String, Integer> getTideDataDifferentValue(String oriPath, String checkPath, String type){
        HashMap<String, Integer> different = new HashMap();
        if (!new File(oriPath).exists()) {
            logger.error("标准文件-- "+ oriPath +" --不存在,请在文件夹中放入标准文件");
        }
        if (!new File(checkPath).exists()) {
            logger.error("标准文件对应的质控标准文件-- "+ checkPath +" --不存在,请在质检后重新执行此程序");
        }

        if (new File(oriPath).exists() && new File(checkPath).exists()) {

            HashMap<String, Integer> oriData = new HashMap<>();
            HashMap<String, Integer> checkData = new HashMap<>();
            if("T023".equals(type)){
                oriData = new T023(oriPath).getData().getData();
                checkData = new T023(checkPath).getData().getData();
            }else if("T022".equals(type)){
                oriData = new T022(oriPath).getData().getData();
                checkData = new T022(checkPath).getData().getData();
            }else if("T021".equals(type)){
                oriData = new T021(oriPath).getData().getData();
                checkData = new T021(checkPath).getData().getData();
            }
            different = getDifferentEntry(oriData, checkData);
            readFile.add(oriPath);  //对比完成，将已完成的文件放入已读文件列表
        }
        return different;
    }
}
